#include "Subsystems/BlockBehaviors/SubsystemGrassTrapBlockBehavior.h"
#include "Log.h"
#include "GameSingleton.h"
#include "Components/ComponentMiner.h"
#include "Components/ComponentBody.h"
#include "Subsystems/SubsystemTerrain.h"

#include "Blocks/GrassTrapBlock.h"

#include "Blocks/OakLeavesBlock.h"
#include "Blocks/BirchLeavesBlock.h"
#include "Blocks/MimosaLeavesBlock.h"
#include "Blocks/SpruceLeavesBlock.h"
#include "Blocks/TallSpruceLeavesBlock.h"

namespace PocketSurvival
{

    SubsystemGrassTrapBlockBehavior::SubsystemGrassTrapBlockBehavior()
    {
        m_handleBlocks.push_back(GrassTrapBlock::Index());
    }

    void SubsystemGrassTrapBlockBehavior::onCollide(const CellFace &cellFace, float velocity, ComponentBody *componentBody)
    {
        if (componentBody->mass > 15.0f && cellFace.face == 4)
        {
            m_trapValuesMutex.lock();

            auto it = m_trapValues.find(cellFace.point);
            if(it == m_trapValues.end())
            {
                m_trapValues.emplace(cellFace.point, -velocity);
            }
            else
            {
                it->second -= velocity;
            }

            m_trapValuesMutex.unlock();
        }
    }

    void SubsystemGrassTrapBlockBehavior::update(float dt)
    {
        std::lock_guard<std::mutex> lk(m_trapValuesMutex);

        for (auto it = m_trapValues.begin(); it != m_trapValues.end(); ++it)
        {
            if (it->second > 1.0f)
            {
                if (m_terrain->getCellContents(it->first) == GrassTrapBlock::Index())
                {
                    m_terrain->destroyCell(0, it->first.posX, it->first.posY, it->first.posZ, 0, false);
                }
                it->second = 0.0f;
            }
            else
            {
                it->second -= 0.5f * dt;
            }
            if(it->second <= 0.0f)
            {
                m_toRemove.push_back(it->first);
            }
        }
        for(auto it = m_toRemove.begin(); it != m_toRemove.end(); ++it)
        {
            auto trapValuesIt = m_trapValues.find(*it);
            if(trapValuesIt != m_trapValues.end())
            {
                m_trapValues.erase(trapValuesIt);
            }
        }
        m_toRemove.clear();
    }

    void SubsystemGrassTrapBlockBehavior::load(const nlohmann::json &json)
    {
        m_terrain = GameSingleton::singletonPtr->getSingleton<SubsystemTerrain>();
    }

    static const std::string subsystemName = "GrassTrapBlockBehavior";
    const std::string &SubsystemGrassTrapBlockBehavior::getName() const
    {
        return subsystemName;
    }
    SubUpdateType SubsystemGrassTrapBlockBehavior::getUpdateType()
    {
        return SubUpdateType::MultiThreadUpdate;
    }
}